﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using AIMLbot;

namespace simWaifu
{
    public partial class FormMain : Form
    {
        private FormDebug frmDebug = null;
        private FormChatLog frmChatLog = null;
        private FormChangeMood frmMood = null;
        private FormBasicSettings frmBasicSettings = null;

        private string currentMessage = "";
        private int currentMessageCharsShown = 0;
        
        // chatbot stuff
        private Bot chatBot = null;
        private User chatUser;
        private Request lastRequest = null;
        private Result lastResult = null;

        public FormMain()
        {
            InitializeComponent();
        }

        // (re-)Initialize the ChatBot
        public void InitializeChatBot()
        {
            DebugMessageHandler.WriteMsgLine("Initializing chatbot.");

            // by default use app path where a working version should be installed
            string configPathName = Path.Combine(Application.StartupPath, "config");
            string configFile = Path.Combine(configPathName, "Settings.xml");
            string aimlPathName = Path.Combine(Application.StartupPath, "aiml");

            // check if the currently set waifu folder contains the config subfolder
            string waifuFolder = Properties.Settings.Default.WaifuFolder;
            if (System.IO.Directory.Exists(Path.Combine(waifuFolder, "config")))
            {
                configPathName = Path.Combine(waifuFolder, "config");
                configFile = Path.Combine(configPathName, "Settings.xml");
            }
            if (System.IO.Directory.Exists(Path.Combine(waifuFolder, "aiml")))
            {
                aimlPathName = Path.Combine(waifuFolder, "aiml");
            }

            DebugMessageHandler.WriteMsgLine("Path to config files: " + configPathName);
            DebugMessageHandler.WriteMsgLine("Config file: " + configFile);
            DebugMessageHandler.WriteMsgLine("Path to aiml database: " + aimlPathName);

            chatBot = new Bot();
            chatBot.loadSettings(configFile);
            chatUser = new User("DefaultUser", this.chatBot);
            
            try
            {
                string reduceFileName = Path.Combine(aimlPathName, "Reduce.aiml");
                AIMLbot.Utils.AIMLLoader loader = new AIMLbot.Utils.AIMLLoader(this.chatBot);
                this.chatBot.isAcceptingUserInput = false;
                loader.loadAIML(aimlPathName);
                this.chatBot.isAcceptingUserInput = true;
            }
            catch (Exception ex)
            {
                DebugMessageHandler.WriteErrorLine("Could not initialize the chatbot!");
                DebugMessageHandler.WriteErrorLine(ex.Message);
            }
        }

        // Derp. This method DOES save the chatbot. 
        // But the mind file is ~60MB big, so it´s useless.
        public void SaveChatBot()
        {
            try
            {
                string saveFile = Path.Combine(Properties.Settings.Default.WaifuFolder, "waifuChat.dat");
                if (this.chatBot.Size > 0)
                {
                    this.chatBot.isAcceptingUserInput = false;
                    this.chatBot.saveToBinaryFile(saveFile);
                    this.chatBot.isAcceptingUserInput = true;
                }
            }
            catch (Exception ex)
            {
                DebugMessageHandler.WriteErrorLine( "Could not write memory file." + ex.Message );
            }
        }


        //
        // Tool methods.
        //

        public void UpdateTitlebar()
        {
            this.Text = Waifu.gender + " " + Waifu.waifuName;
            if (Properties.Settings.Default.ShowMoodName)
            {
                if (timerWelcomeMode.Enabled)
                {
                    this.Text += " (welcome)";
                }
                else
                {
                    this.Text += (" (" + Waifu.GetCurrentMood() + ")");
                }
            }
        }

        // temporarily disable TopMost stuff
        // (when sub forms are shown avoid hiding them)
        public void TopMostDisable()
        {
            TopMost = false;
            alwaysOnTopToolStripMenuItem1.Enabled = false;
        }

        // enable TopMost stuff again
        public void TopMostEnable()
        {
            TopMost = Properties.Settings.Default.AlwaysOnTop;
            alwaysOnTopToolStripMenuItem1.Enabled = true;
        }
        
        private void FirstStartEver()
        {
            //Properties.Settings.Default.Reload();

            // set the waifu folder to the demo data set
            Properties.Settings.Default.WaifuDataFolder = 
                Path.Combine(Application.StartupPath, "data");

            // show info box
            AboutBox about = new AboutBox();
            about.ShowDialog();
            about.Dispose();

            Properties.Settings.Default.FirstStartEver = false;
        }

        public void InitializeTimers()
        {
            if (Properties.Settings.Default.WelcomeModeActive)
            {
                timerWelcomeMode.Interval = Properties.Settings.Default.WelcomeModeDuration * 1000;
                timerWelcomeMode.Start();
                ChangePicSoundMessage();
            }
            else
            {
                if (Properties.Settings.Default.AutoChangeInsideMood)
                    StartInsideMoodChanger();
                if (Properties.Settings.Default.AutoChangeOfMood)
                    StartMoodChanger();
            }
        }

        private void StartMoodChanger()
        {
            //stop first if running to avoid confusion
            if (timerMoodChanger.Enabled)
                timerMoodChanger.Stop();
            if (Properties.Settings.Default.AutoChangeOfMood)
            {
                // property setting is in minutes
                int rand = Waifu.rand.Next(Properties.Settings.Default.AutoChangeOfMoodMinTime * 1000 * 60,
                    Properties.Settings.Default.AutoChangeOfMoodMaxTime * 1000 * 60);
                DebugMessageHandler.WriteMsgLine("Next mood change in: " + (rand / 60000).ToString());
                timerMoodChanger.Interval = rand;
                timerMoodChanger.Start();
            }
        }

        private void StartInsideMoodChanger()
        {
            // stop first to avoid confusion
            if (timerInsideMoodChanger.Enabled)
                timerInsideMoodChanger.Stop();
            if (Properties.Settings.Default.AutoChangeInsideMood)
            {
                // property setting is in seconds
                int rand = Waifu.rand.Next(Properties.Settings.Default.AutoChangeInsideMoodMinTime * 1000,
                    Properties.Settings.Default.AutoChangeInsideMoodMaxTime * 1000);
                DebugMessageHandler.WriteMsgLine("Next inside mood change in: " + (rand / 1000).ToString());
                timerInsideMoodChanger.Interval = rand;
                timerInsideMoodChanger.Start();
            }
        }

        public void ChangePicSoundMessage()
        {
            UpdateTitlebar();
            ChangeMessage();
            ChangeSound();
            ChangePicture();
        }

        private void ChangeMessage(string newMessage)
        {
            currentMessage = newMessage;

            SpeechHandler.Say(newMessage);
            
            // if typer is disabled, show whole text at once
            if (Properties.Settings.Default.ActivateTyper)
                currentMessageCharsShown = 0;
            else
                currentMessageCharsShown = currentMessage.Length;

            if (currentMessage.Length > 0)
            {
                UpdateMessageVisibility(true);
                timerMsgTyper.Interval = Properties.Settings.Default.TyperDelay;
                timerMsgTyper.Start();
            }
            else            
            {
                currentMessageCharsShown = 0;
                UpdateMessageVisibility(false);
                timerMsgTyper.Stop();
            }
            // Fader must not be running if typer is active (or message is empty).
            timerMsgFader.Stop();
            UpdateMessageText();
        }

        public void ChangeMessage()
        {
            string newMessage = "";
            // welcome mode?
            //if (timerWelcomeMode.Enabled)
            //{
            //    newMessage = Waifu.WelcomeMessage();
            //}
            //else
            {
                newMessage = Waifu.ChangeMoodMessage();
            }
            ChangeMessage(newMessage);
        }

        public void ChangeSound()
        {
            string snd= "";
            //if(timerWelcomeMode.Enabled)
            //{
            //    snd= Waifu.WelcomeSound();
            //}
            //else
            {
                snd = Waifu.ChangeMoodSound();
            }

            if(snd.Equals(""))
            {
                DebugMessageHandler.WriteMsgLine("No sound files available for current mood.");
            }
            else
            {
                axWindowsMediaPlayer1.URL = snd;
                DebugMessageHandler.WriteMsgLine("Playing new sound: " + snd);
            }
        }

        public void ChangePicture()
        {
            string newPic = Waifu.ChangeMoodPicture();
            DebugMessageHandler.WriteMsgLine("newpic = " + newPic);
            if (newPic.Equals(""))
            {
                DebugMessageHandler.WriteMsgLine("No picture file available.");
            }
            else
            {
                // (simply loading does not work with animated gifs)
                // pictureBox1.Load(newPic);

                if (pictureBox1.Image != null)
                    pictureBox1.Image.Dispose();
                pictureBox1.Image = Image.FromFile(newPic);
                if (pictureBox1.SizeMode == PictureBoxSizeMode.AutoSize)
                    this.Size = pictureBox1.Image.Size;
            }
        }


        //
        // message helper functions
        //
        // these should be the only ones which directly access the object
        // which shows the message (label,button,...)
        // so the object type can be changed easier if necessary
        //

        private void InitializeMessageObject()
        {
            UpdateMessageVisibility(false);

            LabelOldMessage.Parent = pictureBox1;
            LabelOldMessage.BackColor = System.Drawing.Color.Transparent;

            LabelCurrentMessage.Parent = pictureBox1;
            LabelCurrentMessage.BackColor = System.Drawing.Color.Transparent;
            
            timerMsgCursorBlink.Start();
        }

        // show the currently active part of the current message
        string newText = "";
        string oldText = "";
        private void UpdateMessageText()
        {
            // check if alignment was changed
            if (Properties.Settings.Default.TyperPosition.Equals("Center"))
            {
                LabelCurrentMessage.TextAlign = ContentAlignment.MiddleCenter;
                LabelOldMessage.TextAlign = ContentAlignment.MiddleCenter;
            }
            else if (Properties.Settings.Default.TyperPosition.Equals("Left"))
            {
                LabelCurrentMessage.TextAlign = ContentAlignment.MiddleLeft;
                LabelOldMessage.TextAlign = ContentAlignment.MiddleLeft;
            }
            else
            {
                DebugMessageHandler.WriteErrorLine("Unknown alignment setting for message. Setting to Center. "
                    + Properties.Settings.Default.TyperPosition);
                LabelCurrentMessage.TextAlign = ContentAlignment.MiddleCenter;
                LabelOldMessage.TextAlign = ContentAlignment.MiddleCenter;
            }

            if (currentMessageCharsShown == 0)
            {
                //flush old texts
                oldText = "";
                newText = "";
            }

            // don´t need to write something if the message is empty...            
            if ((currentMessage.Length > 0)&&(currentMessageCharsShown>0))
            {
                if (currentMessageCharsShown <= currentMessage.Length)
                {
                    //int cutOffFirstChars = 0;
                    //int maxMessageLength = 50;
                    //if (currentMessageCharsShown - maxMessageLength > 0)
                    //{
                    //    cutOffFirstChars = currentMessageCharsShown - maxMessageLength;
                    //}
                    //newText = currentMessage.Substring(cutOffFirstChars, currentMessageCharsShown - cutOffFirstChars);
                    //DebugMessageHandler.WriteMsgLine("UpdateMessageText(): newText: " + newText);

                    newText += currentMessage.Substring(currentMessageCharsShown - 1, 1);
                    //wrap
                    int maxMessageLength = 50;
                    if (newText.Length > maxMessageLength)
                    {
                        // flush old text
                        oldText = "";
                        // show label (it´s invisible when not needed)
                        LabelOldMessage.Visible = true;

                        bool wrap = true;
                        if (wrap)
                        {
                            // wordwrap
                            int lastPossibleWrap = maxMessageLength;
                            for (int i=0; i < maxMessageLength; i++)
                            {
                                // for now only wrappable at spaces
                                if (newText.Substring(i, 1).Equals(" "))
                                    lastPossibleWrap = i; //found wrap position
                            }
                            oldText = newText.Substring(0, lastPossibleWrap);
                            newText = newText.Substring(lastPossibleWrap, newText.Length-lastPossibleWrap);
                        }
                        else
                        {
                            // nowrap (dead code, don´t think anybody does NOT want wordwrap)
                            oldText = newText.Substring(0, maxMessageLength);
                            newText = newText.Substring(maxMessageLength, 1);
                        }
                    }
                }
                else
                {
                    DebugMessageHandler.WriteErrorLine("UpdateMessageText(): currentMessageCharsShown is bigger than currentMessage.Length!");
                }

            }
            
            LabelCurrentMessage.Text = newText;
            if (currentMessageCharsShown < currentMessage.Length)
            {
                if (Properties.Settings.Default.ActivateCursor)
                    LabelCurrentMessage.Text += Properties.Settings.Default.CursorType;
            }

            LabelOldMessage.Text = oldText;
        }

        // toggle message visibility
        private void UpdateMessageVisibility(bool bVisible)
        {
            LabelCurrentMessage.Visible = bVisible;
            
            // only hide old message, it will be shown only if needed
            if(!bVisible)
                LabelOldMessage.Visible = bVisible;
        }

        // called after message font and/or color have been changed
        public void UpdateMessageFont()
        {
            LabelCurrentMessage.Font = Properties.Settings.Default.FontMessage;
            LabelCurrentMessage.ForeColor = Properties.Settings.Default.FontMessageColor;

            LabelOldMessage.Font = Properties.Settings.Default.FontMessage;
            LabelOldMessage.ForeColor = Properties.Settings.Default.FontMessageColor;
        }
   
        
        //
        // Event handlers.
        //

        private void FormMain_Load(object sender, EventArgs e)
        {
            // if waifuFolder is empty:
            // (happens when simWaifu is started the first time)
            // -> set app path as waifu folder
            if (Properties.Settings.Default.WaifuFolder.Equals(""))
                Properties.Settings.Default.WaifuFolder = Application.StartupPath;

            // if waifuFolder does not exist anymore:
            // (happens when user deleted the last active waifu folder)
            // -> set back to app path
            if (!System.IO.Directory.Exists(Properties.Settings.Default.WaifuFolder))
                Properties.Settings.Default.WaifuFolder = Application.StartupPath;

            if (DebugMessageHandler.bLogErrors)
            {
                frmDebug = new FormDebug();
                frmDebug.Show(); // show non-modal
                // activate debug message handling
                // (connect to debug form before initializing 
                // so the form can log errors in case there is 
                // a problem opening the output file)
                DebugMessageHandler.ConnectToDebugForm(frmDebug);
                DebugMessageHandler.Initialize();
            }

            // start chatlog
            ChatLogger.Initialize();

            // first start ever?
            if (Properties.Settings.Default.FirstStartEver)
                FirstStartEver();

            Waifu.Initialize();
            
            // todo: load settings which are not handled automatically:
            // window size (need to try out, but VB didn´t set that even if data was bound) 
            // load internal font if type is != -1 
            // -1 = system font. 
            // 0,1,2,3,... = internal font(s)
            this.Size = Properties.Settings.Default.MainFormSize; // not bound because not supported
            TopMostEnable(); // not bound because disabling temporary was overwritten
            alwaysOnTopToolStripMenuItem1.Checked = this.TopMost;

            // activate speech synth
            // !!switching back to Anna can lead to a crash. So Feature is deactivated by default!!!
            activateVoiceToolStripMenuItem.Checked = false; // Properties.Settings.Default.SpeechSynthEnabled;
            if (activateVoiceToolStripMenuItem.Checked) //Properties.Settings.Default.SpeechSynthEnabled)
            {
                SpeechHandler.Initialize();
            }

            // Initialize the object which displays the messages
            // put into own method to allow easier change of type (label, button, ...)
            InitializeMessageObject();
            
            UpdateTitlebar();         

            // toDo: embed some app specific fonts
            InitializeTimers();         
            ChangePicSoundMessage();

            InitializeChatBot();
        }

        private void FormMain_Closing(object sender, FormClosingEventArgs e)
        {
            // haha, nope. That creates a 60MB file.
            // gotta find a better way to store only user specific variables
            //SaveChatBot();
            
            // save settings etc
            DebugMessageHandler.ShutDown();
            Properties.Settings.Default.MainFormSize = this.Size;
            Properties.Settings.Default.Save();
        }

        private void Label1_Click(object sender, EventArgs e)
        {
            ChangePicSoundMessage();
        }

        private void aboutToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            AboutBox about = new AboutBox();
            about.ShowDialog();
            about.Dispose();
        }

        private void debugWindowToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if ((frmDebug==null) || frmDebug.IsDisposed)
            {
                DebugMessageHandler.bLogErrors = true;
                if (!DebugMessageHandler.bInitialized)
                    DebugMessageHandler.Initialize();
                frmDebug = new FormDebug();
                frmDebug.Show();
                DebugMessageHandler.ConnectToDebugForm(frmDebug);
            }
            else
            {
                frmDebug.Close();
            }
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            ChangePicSoundMessage();
        }

        private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            // stop welcome mode if it´s running
            if (timerWelcomeMode.Enabled)
                timerWelcomeMode.Stop();
            StartInsideMoodChanger();
            StartMoodChanger();
            Waifu.ChangeRegularMoodRandom();
            Waifu.SetMoodType(Waifu.MoodType.regular);
            ChangePicSoundMessage();
        }

        private void changeRandomlyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Waifu.ChangeRegularMoodRandom();
            ChangePicSoundMessage();
        }

        private void rescanToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Waifu.Initialize();
        }

        private void hideShowMenubarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.menuStrip1.Visible = !this.menuStrip1.Visible;
        }

        private void alwaysOnTopToolStripMenuItem1_Click(object sender, EventArgs e)
        {
             this.TopMost = !this.TopMost;
            Properties.Settings.Default.AlwaysOnTop = this.TopMost;
            alwaysOnTopToolStripMenuItem1.Checked = this.TopMost;
        }

        private void settingsToolStripMenuItem1_Click(object sender, EventArgs e)
        {
           if (frmBasicSettings == null)
            {
                frmBasicSettings = new FormBasicSettings(this);
                frmBasicSettings.Show();
            }
            else if (frmBasicSettings.IsDisposed)
            {
                frmBasicSettings = new FormBasicSettings(this);
                frmBasicSettings.Show();
            }
            else
            {
                frmBasicSettings.Close();
            }
        }

        private void stretchToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            Properties.Settings.Default.PictureBoxSizeMode = pictureBox1.SizeMode;
        }

        private void zoomToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
            Properties.Settings.Default.PictureBoxSizeMode = pictureBox1.SizeMode;
        }

        private void autoSizeToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
            Properties.Settings.Default.PictureBoxSizeMode = pictureBox1.SizeMode;
        }

        private void centerToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
            Properties.Settings.Default.PictureBoxSizeMode = pictureBox1.SizeMode;
        }

        private void normalToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            pictureBox1.SizeMode = PictureBoxSizeMode.Normal;
            Properties.Settings.Default.PictureBoxSizeMode = pictureBox1.SizeMode;
        }

        private void changeToToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (frmMood == null)
            {
                frmMood = new FormChangeMood(this);
                frmMood.Show();
            }
            else if (frmMood.IsDisposed)
            {
                frmMood = new FormChangeMood(this);
                frmMood.Show();
            }
            else
            {
                frmMood.Close();
            }
        }

        private void changeRandomToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Waifu.ChangeRegularMoodRandom();
            ChangePicSoundMessage();
        }

        private void rescanToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Waifu.Initialize();
        }

        private void exitToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        public void EventChecker_CheckForTimeBased()
        {
            // check if it´s wake up time
            if(DateTimeHelper.IsInThePast(Properties.Settings.Default.SleepCycleFixedWakeUpTime))
            {
                DebugMessageHandler.WriteMsgLine("EventChecker: Wake up time is in the past.");
                DebugMessageHandler.WriteMsgLine("EventChecker: ----> Waking up now.");
                Properties.Settings.Default.SleepCycleFixedWakeUpTime = DateTimeHelper.GetNextTimeWhen(Properties.Settings.Default.SleepCycleFixedWakeUpTime);
                DebugMessageHandler.WriteMsgLine("EventChecker: ----> Next wake up at: " + Properties.Settings.Default.SleepCycleFixedWakeUpTime.ToString());
            }
            else
            {
                DebugMessageHandler.WriteMsgLine("EventChecker: Wake up time lies in the future.");
            }

            if(DateTimeHelper.IsInThePast(Properties.Settings.Default.SleepCycleFixedGoToBedTime))
            {
                DebugMessageHandler.WriteMsgLine("EventChecker: Go to bed time is in the past.");
                DebugMessageHandler.WriteMsgLine("EventChecker: ----> going to bed.");
                Properties.Settings.Default.SleepCycleFixedGoToBedTime = DateTimeHelper.GetNextTimeWhen(Properties.Settings.Default.SleepCycleFixedGoToBedTime);
                DebugMessageHandler.WriteMsgLine("EventChecker: ----> Next go to bed: " + Properties.Settings.Default.SleepCycleFixedGoToBedTime.ToString());
            }
            else
            {
                DebugMessageHandler.WriteMsgLine("EventChecker: Go to bed time lies in the future.");
            }
        }

        private void chatToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // todo: maybe move the code to own methods: StartChatmode / StopChatmode
            // check if sleep mode active, don´t allow starting to chat / ask if user wants to wake up waifu

            if (!textInput.Visible)
            {
                textInput.Visible = true;
                timerMoodChanger.Stop();
                timerInsideMoodChanger.Stop();
                if (timerWelcomeMode.Enabled)
                    timerWelcomeMode.Stop();

                Waifu.SetMoodType(Waifu.MoodType.chat);
                UpdateTitlebar();
                ChangePicSoundMessage();
            }
            else
            {
                textInput.Visible = false;
                Waifu.SetMoodType(Waifu.MoodType.regular);
                Waifu.ChangeRegularMoodRandom();
                UpdateTitlebar();
                ChangePicSoundMessage();
                if(Properties.Settings.Default.AutoChangeOfMood)
                    timerMoodChanger.Start();
                if (Properties.Settings.Default.AutoChangeInsideMood)
                    timerInsideMoodChanger.Start();
            }
        }

        private void processInputFromUser()
        {
            // chatbot must exist
            if (chatBot == null)
            {
                DebugMessageHandler.WriteErrorLine("chatbot is null!");
                return;
            }

            // grab the reply from AIMLBot
            if (this.chatBot.isAcceptingUserInput)
            {
                string rawInput = this.textInput.Text;
                this.textInput.Text = string.Empty;
                ChatLogger.WriteChatLine(Waifu.anonName + "> " + rawInput);
                Request myRequest = new Request(rawInput, this.chatUser, this.chatBot);
                Result myResult = this.chatBot.Chat(myRequest);
                this.lastRequest = myRequest;
                this.lastResult = myResult;
                ChatLogger.WriteChatLine(Waifu.waifuName + "> " + myResult.Output);

                // todo: change to chat sub-mood depending on response
                // for now this is just a skeleton
                string response = myResult.Output;
                DebugMessageHandler.WriteMsgLine("Chat response = " + response);
                string cleanResponse = myResult.Output; // assume it´s clean
                {
                    string submood = "";
                    if (response.Contains("?"))
                    {
                        submood = "question";
                    }
                    if (response.Contains("!"))
                    {
                        submood = "exclamation";
                    }

                    // response can contain tokens in brackets, for example [angry]
                    // for now, only the first token will be stored
                    // todo: build list of all tokens in response
                    if (response.Contains("[") && response.Contains("]"))
                    {
                        // need to build clean response without the token
                        cleanResponse = "";
                        string token = "";
                        bool bInsideToken = false;
                        bool bTokenFinished = false;
                        for (int i = 0; i < response.Length; i++)
                        {
                            char curChar = response[i];

                            // build clean response
                            if((!bInsideToken)&&(curChar!='['))
                                cleanResponse += curChar;

                            // build token
                            if (curChar == ']')
                            {
                                bInsideToken = false;
                                bTokenFinished = true;
                            }
                            if (!bTokenFinished && bInsideToken)
                                token += curChar;
                            if (curChar == '[')
                                bInsideToken = true;
                        }
                        if (token.Length == 0)
                            DebugMessageHandler.WriteMsgLine("Chat response contained '[]', but no token!");
                        submood = token;
                    }
                    DebugMessageHandler.WriteMsgLine("Chat submood = " + submood);
                    Waifu.curSubMood = submood;
                }
                
                this.textInput.Text = "";
                ChangeMessage(cleanResponse);

                ChangePicture();
            }
            else
            {
                DebugMessageHandler.WriteErrorLine("Bot not accepting user input.");
            }
        }

        private void textInput_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 13)
            {
                this.processInputFromUser();
            }
        }

        private void rescanAIMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // simply create new cBot, garbage collector will dispose of the last one
            InitializeChatBot();
        }

        private void chatLogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if ((frmChatLog == null) || frmChatLog.IsDisposed)
            {
                ChatLogger.bLogChat = true;
                if (!ChatLogger.bInitialized)
                    ChatLogger.Initialize();
                frmChatLog = new FormChatLog();
                frmChatLog.Show();
                ChatLogger.ConnectToChatForm(frmChatLog);
            }
            else
            {
                frmChatLog.Close();
            }
        }

        private void activateVoiceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Properties.Settings.Default.SpeechSynthEnabled = !Properties.Settings.Default.SpeechSynthEnabled;
            activateVoiceToolStripMenuItem.Checked = !activateVoiceToolStripMenuItem.Checked;
            //if (Properties.Settings.Default.SpeechSynthEnabled)
            if(activateVoiceToolStripMenuItem.Checked)
                SpeechHandler.Initialize();
            else
                SpeechHandler.ShutDown();
        }

        private void selectVoiceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SpeechHandler.SelectVoice();
        }

        private void settingsChatToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string file = Path.Combine(Application.StartupPath, "config", "Settings.xml");
            FormChatSettings chatSettings = new FormChatSettings(file);
            chatSettings.ShowDialog();
            InitializeChatBot();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.RootFolder = Environment.SpecialFolder.MyComputer;
            folderBrowserDialog1.SelectedPath = Properties.Settings.Default.WaifuFolder;
            if (folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Properties.Settings.Default.WaifuFolder = folderBrowserDialog1.SelectedPath;
                DebugMessageHandler.WriteMsgLine("Selected folder: " + Properties.Settings.Default.WaifuFolder);
                InitializeChatBot();
                Waifu.Initialize();
            }
        }


        //
        // Timer stuff
        //

        private void timerMsgFader_Tick(object sender, EventArgs e)
        {
            // Fader should not be running while Typer runs.
            if (timerMsgTyper.Enabled)
                DebugMessageHandler.WriteErrorLine("timerMsgFader_Tick: Fader is running, too!");

            // Fader should not be running on empty message.
            if (currentMessage.Length == 0)
                DebugMessageHandler.WriteErrorLine("timerMsgFader_Tick: Fader is running, too!");

            DebugMessageHandler.WriteMsgLine("timerMsgFader_Tick: hiding message now.");
            timerMsgFader.Stop();
            UpdateMessageVisibility(false);
            ChangeMessage("");
        }

        private void timerMsgTyper_Tick(object sender, EventArgs e)
        {
            // Fader should not be running while Typer runs.
            if (timerMsgFader.Enabled)
                DebugMessageHandler.WriteErrorLine("timerMsgTyper_Tick: Fader is running, too!");

            // Typer should only run if there is a message.
            if (currentMessage.Length > 0)
            {
                // do we have more characters left?
                if (currentMessageCharsShown < currentMessage.Length)
                {
                    currentMessageCharsShown++;
                    UpdateMessageText();
                }
                else
                {
                    timerMsgTyper.Stop();
                    timerMsgFader.Interval = Properties.Settings.Default.FaderDelay * 1000;
                    timerMsgFader.Start();
                }
            }
            else
            {
                DebugMessageHandler.WriteErrorLine("timerMsgTyper_Tick: currentMessage.Length=0! Timer should not be ticking!");
            }
        }

        private void timerMsgCursorBlink_Tick(object sender, EventArgs e)
        {
            //messageCursorVisible = !messageCursorVisible;
        }

        private void timerWelcomeMode_Tick(object sender, EventArgs e)
        {
            DebugMessageHandler.WriteMsgLine("welcome tick");
            timerWelcomeMode.Stop();

            // don´t stay in welcome mode eternally if user only clicks
            Waifu.SetMoodType(Waifu.MoodType.regular);
            Waifu.ChangeRegularMoodRandom();
            ChangePicSoundMessage();

            // try to start mood changers 
            // (they won´t start if it´s disabled in the settings)
            StartInsideMoodChanger();
            StartMoodChanger();
        }

        private void timerInsideMoodChanger_Tick(object sender, EventArgs e)
        {
            DebugMessageHandler.WriteMsgLine("inside mood changer tick");
            ChangePicSoundMessage();
            // stop and restart if still active
            StartInsideMoodChanger();
        }

        private void timerMoodChanger_Tick(object sender, EventArgs e)
        {
            DebugMessageHandler.WriteMsgLine("mood changer tick");
            Waifu.ChangeRegularMoodRandom();
            ChangePicSoundMessage();
            // restart the inside mood changer to avoid showing new picture too fast
            StartInsideMoodChanger();
            // stop and restart if still active
            StartMoodChanger();
        }

        private void timerEventTimeBased_Tick(object sender, EventArgs e)
        {
            EventChecker_CheckForTimeBased();
        }

    }
}
